//
//  WDTableView.swift
//  UIKitExtentions
//
//  Created by Alean on 2023/5/10.
//

import Foundation
public typealias ObjectRenderable = NSObject & MVVMBaseModelProtocol
//public typealias TableRenderable = UITableViewCell & MVVMBaseViewModelProtocol

open class TableDataSource: NSObject, UITableViewDelegate, UITableViewDataSource {
    fileprivate weak var tableView: UITableView?

    internal final var onScroll: ((UIScrollView) -> Void)?
    @discardableResult
    public final func onScroll(_ handler: @escaping ((UIScrollView) -> Void)) -> Self {
        onScroll = handler
        return self
    }

    internal final var onCellSelected: ((UITableView, IndexPath) -> Void)?
    @discardableResult
    public final func onCellSelected(_ handler: @escaping ((UITableView, IndexPath) -> Void)) -> Self {
        onCellSelected = handler
        return self
    }

    internal final var dynamicRowHeight: ((UITableView, IndexPath) -> CGFloat)?
    @discardableResult
    public final func dynamicRowHeight(_ handler: @escaping ((UITableView, IndexPath) -> CGFloat)) -> Self {
        dynamicRowHeight = handler
        return self
    }

    internal final var dynamicHeightForHeaderInSection: ((UITableView, Int) -> CGFloat)?
    @discardableResult
    public final func dynamicHeightForHeaderInSection(_ handler: @escaping ((UITableView, Int) -> CGFloat)) -> Self {
        dynamicHeightForHeaderInSection = handler
        return self
    }

    internal final var dynamicHeightForFooterInSection: ((UITableView, Int) -> CGFloat)?
    @discardableResult
    public final func dynamicHeightForFooterInSection(_ handler: @escaping ((UITableView, Int) -> CGFloat)) -> Self {
        dynamicHeightForFooterInSection = handler
        return self
    }

    internal final var numberOfSections: ((UITableView) -> Int)?
    @discardableResult
    public final func numberOfSections(_ handler: @escaping ((UITableView) -> Int)) -> Self {
        numberOfSections = handler
        return self
    }

    internal final var viewForHeaderInSection: ((UITableView, Int) -> UIView)?
    @discardableResult
    public final func viewForHeaderInSection(_ handler: @escaping ((UITableView, Int) -> UIView)) -> Self {
        viewForHeaderInSection = handler
        return self
    }

    internal final var viewForFooterInSection: ((UITableView, Int) -> UIView)?
    @discardableResult
    public final func viewForFooterInSection(_ handler: @escaping ((UITableView, Int) -> UIView)) -> Self {
        viewForFooterInSection = handler
        return self
    }

    internal final var items: ((UITableView, IndexPath) -> [ObjectRenderable]?)?
    @discardableResult
    public final func items(_ handler: @escaping ((UITableView, IndexPath) -> [ObjectRenderable]?)) -> Self {
        items = handler
        return self
    }

    internal final var cellForRow: ((UITableView, IndexPath, ObjectRenderable?) -> (UITableViewCell?))?
    @discardableResult
    public final func cellForRow(_ handler: @escaping ((UITableView, IndexPath, ObjectRenderable?) -> (UITableViewCell?))) -> Self {
        cellForRow = handler
        return self
    }

    @discardableResult
    public func cellRegister(_ cellTypes: [UITableViewCell.Type]) -> Self {
        for cellType in cellTypes {
            tableView?.register(cellType)
//            tableView?.register(cellType, forCellReuseIdentifier: cellType.identifier)
        }
        return self
    }

    deinit {
        tableView?.delegate = nil
        tableView?.dataSource = nil
        NotificationCenter.default.removeObserver(self)
    }

    @discardableResult
    public func reload() -> Self {
        tableView?.reloadData()
        return self
    }

//    public init<T: TableRenderable>(tableView: UITableView, cellTypes: [T.Type]) {
    public init(tableView: UITableView) {
      super.init()
        self.tableView = tableView
        tableView.delegate = self
        tableView.dataSource = self
    }

    public func scrollViewDidScroll(_ scrollView: UIScrollView) {
        onScroll?(scrollView)
    }

    public func numberOfSections(in tableView: UITableView) -> Int {
        if let numberOfSections = numberOfSections {
            return numberOfSections(tableView)
        }
        return 1
    }

    public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return items?(tableView, IndexPath(row: 0, section: section))?.count ?? 0
    }

    public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if let items = items, let datas = items(tableView, indexPath), !datas.isEmpty {
            if let cellForRow = cellForRow,
               let cell = cellForRow(tableView, indexPath, datas[safe: indexPath.row])
//                , cell is (any MVVMBaseViewModelProtocol)
            {
                cell.selectionStyle = .none
                return cell
            }
        }
        return UITableViewCell()

//        let cell = tableView.dequeueReusableCell(withIdentifier: WDChooseAddressCell.identifier, for: indexPath) as! WDChooseAddressCell
//        cell.selectionStyle = .none
//        cell.data = data
//        return cell
    }

    public func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
        if let dynamicRowHeight = dynamicRowHeight {
            return dynamicRowHeight(tableView, indexPath)
        }
        return UITableView.automaticDimension
    }

    public func tableView(_ tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat {
        if let dynamicHeightForHeaderInSection = dynamicHeightForHeaderInSection {
            return dynamicHeightForHeaderInSection(tableView, section)
        }
        return 0
//            return UITableView.automaticDimension
    }

    public func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        return viewForHeaderInSection?(tableView, section)
    }

    public func tableView(_ tableView: UITableView, estimatedHeightForFooterInSection section: Int) -> CGFloat {
        if let dynamicHeightForFooterInSection = dynamicHeightForFooterInSection {
            return dynamicHeightForFooterInSection(tableView, section)
        }
        return 0
    }

    public func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
        return viewForFooterInSection?(tableView, section)
    }

    public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
        onCellSelected?(tableView, indexPath)
    }
}

class Model: WDBaseModel {
    
}
class Cell: WDBaseTableCell<Model> {
    
}
//open class WDTableConfig<T: ObjectRenderable> : NSObject {
////open class WDTableConfig<T: ObjectRenderable, C: TableRenderable> : NSObject {
////open class WDTableConfig<T, C> where T: WDBaseModel, C: UITableViewCell {//: NSObject {
//    public var items: [T] = []
//
//    fileprivate weak var dataSource: DataSource?
//
//    public init(tableView: UITableView) {
//        super.init()
//        dataSource = DataSource(tableView: tableView, cellTypes: [Cell.self])
//            .items({ table, index in
//                return [WDBaseModel(), WDBaseModel()]
//            }).cellForRow({ table, index, object in
//                return UITableViewCell()
//            }).dynamicRowHeight({ table, index in
//                return UITableView.automaticDimension
//            }).onCellSelected({ table, index in
//                print("index = \(index)")
//            })
//    }
//
//    enum SomeEnum { //Todo: name me
//        case string(String)
//        case int(Int)
//    }
//    func foo(input: SomeEnum) -> SomeEnum {
//        switch input {
//            case .string(let s):
//                print("This is a String: \(s)")
//                return(.string("abc"))
//            case .int(let i):
//                print("This is an Int: \(i)")
//                return(.int(123))
//        }
//    }
//    func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {
//        // function body goes here
//    }
//    func findIndex<T: Equatable>(of valueToFind: T, in array:[T]) -> Int? {
//        for (index, value) in array.enumerated() {
//            if value == valueToFind {
//                return index
//            }
//        }
//        return nil
//    }
//    protocol Container {
//        associatedtype Item: Equatable
//        mutating func append(_ item: Item)
//        var count: Int { get }
//        subscript(i: Int) -> Item { get }
//
//        associatedtype Iterator: IteratorProtocol where Iterator.Element == Item
//        func makeIterator() -> Iterator
//    }
//    protocol ComparableContainer: Container where Item: Comparable { }

//    protocol SuffixableContainer: Container {
//        associatedtype Suffix: SuffixableContainer where Suffix.Item == Item
//        func suffix(_ size: Int) -> Suffix
//    }
//    extension Container where Item: Equatable {
//        func startsWith(_ item: Item) -> Bool {
//            return count >= 1 && self[0] == item
//        }
//    }
//    extension Container where Item == Double {
//        func average() -> Double {
//            var sum = 0.0
//            for index in 0..<count {
//                sum += self[index]
//            }
//            return sum / Double(count)
//        }
//    }
//    extension Container {
//        func average() -> Double where Item == Int {
//            var sum = 0.0
//            for index in 0..<count {
//                sum += Double(self[index])
//            }
//            return sum / Double(count)
//        }
//        func endsWith(_ item: Item) -> Bool where Item: Equatable {
//            return count >= 1 && self[count-1] == item
//        }
//    }
//    func isAllItemsMatch<A1: MyProtocol, A2: MyProtocol>(_ ite1: A1, _ ite2: A2) -> Bool where A1.MyType == A2.MyType, A1.MyType: Equatable {
//    }
//}

open class WDBaseFormView<State: UIView>: UIView {
    
    public final func formContentView(view: State) -> Self {
        mainView.addSubview(view)
        view.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }
        self.updateConstraintsIfNeeded()
        return self
    }

    internal final var formHeaderView: ((WDBaseFormView<State>) -> UIView?)?
    @discardableResult
    public final func formHeaderView(_ handler: @escaping ((WDBaseFormView<State>) -> UIView?)) -> Self {
        formHeaderView = handler

        if let headerView = formHeaderView?(self) {
            self.topView.addSubview(headerView)
            headerView.snp.makeConstraints { make in
                make.edges.equalToSuperview()
            }
            self.updateConstraintsIfNeeded()
        }

        return self
    }

    internal final var formFooterView: ((WDBaseFormView<State>) -> UIView?)?
    @discardableResult
    public final func formFooterView(_ handler: @escaping ((WDBaseFormView<State>) -> UIView?)) -> Self {
        formFooterView = handler

        if let footerView = formFooterView?(self) {
            self.bottomView.addSubview(footerView)
            footerView.snp.makeConstraints { make in
                make.edges.equalToSuperview()
            }
            self.updateConstraintsIfNeeded()
        }

        return self
    }

    public override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }
    
    public convenience init() {
        self.init(frame: .zero)
    }
    
    public required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    let topView = UIView()
    let bottomView = UIView()
    let mainView = UIView()

    private final func setup() {
        addSubview(topView)
        topView.snp.makeConstraints { make in
            make.left.right.equalToSuperview()
            make.top.equalToSuperview()
        }

        addSubview(bottomView)
        bottomView.snp.makeConstraints { make in
            make.left.right.equalToSuperview()
            make.bottom.equalToSuperview()
        }

        addSubview(mainView)
        mainView.snp.makeConstraints { make in
            make.top.equalTo(topView.snp.bottom)
            make.bottom.equalTo(bottomView.snp.top)
            make.left.right.equalToSuperview()
//            make.height.lessThanOrEqualToSuperview().priority(.high)
        }

        initContent()
    }
    public func initContent() {
        
    }
}

open class WDTableView: WDBaseFormView<UITableView> {
    
    public let tableView: UITableView = {
        let tableView = UITableView(frame: .zero, style: .plain)
        tableView.backgroundColor = .clear
        tableView.separatorStyle = .none
//        tableView.separatorStyle = .singleLine
//        tableView.separatorInset = UIEdgeInsets(top: 0, left: 13, bottom: 0, right: 13)
        tableView.estimatedRowHeight = 0
        tableView.rowHeight = UITableView.automaticDimension

        tableView.estimatedSectionHeaderHeight = 0
        tableView.sectionHeaderHeight = UITableView.automaticDimension

        tableView.estimatedSectionFooterHeight = 0
        tableView.sectionFooterHeight = UITableView.automaticDimension

        tableView.showsHorizontalScrollIndicator = false
        tableView.showsVerticalScrollIndicator = false
//        tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 67, right: 0)

        tableView.tableFooterView = UIView()
        if #available(iOS 15.0, *) {
            tableView.sectionHeaderTopPadding = 0
        } else {
            // Fallback on earlier versions
        }
        if #available(iOS 11.0, *) {
            tableView.contentInsetAdjustmentBehavior = .never
        } else {
            topViewController()?.automaticallyAdjustsScrollViewInsets = false
        }
        return tableView
    }()

    public lazy var dataSource: TableDataSource = TableDataSource(tableView: tableView)

    public override func initContent() {
        super.initContent()
        formContentView(view: tableView)

//        let tableView = WDTableView().formHeaderView { table in
//            let view = UIView()
//            view.backgroundColor = UIColor.green
//            
//            let v = UIView()
//            v.backgroundColor = UIColor.red
//            view.addSubview(v)
//            v.snp.makeConstraints { make in
//                make.left.equalToSuperview()
//                make.top.equalToSuperview()
//                make.height.equalTo(40)
//                make.width.equalTo(200)
//                make.bottom.equalToSuperview()
//            }
//            return view
//        }.formFooterView { table in
//            let view = UIView()
//            view.backgroundColor = UIColor.yellow
//            let v = UIView()
//            v.backgroundColor = UIColor.red
//            view.addSubview(v)
//            v.snp.makeConstraints { make in
//                make.left.equalToSuperview()
//                make.top.equalToSuperview()
//                make.height.equalTo(50)
//                make.width.equalTo(100)
//                make.bottom.equalToSuperview()
//            }
//            return view
//        }

//        let dataSource = DataSource(tableView: tableView)
//            .cellRegister([Cell.self])
//            .items({ table, index in
//                return [WDBaseModel(), WDBaseModel()]
//            }).cellForRow({ table, index, object in
//                return UITableViewCell()
//            }).dynamicRowHeight({ table, index in
//                return UITableView.automaticDimension
//            }).onCellSelected({ table, index in
//                print("index = \(index)")
//            })
        
//        dataSource
//            .cellRegister([Cell.self])
//            .cellForRow({ table, index, object in
//                return UITableViewCell()
//            })
//            .items({ table, index in
//                return [WDBaseModel(), WDBaseModel()]
//            })
//            .onCellSelected { table, index in
//                print("index = \(index)")
//            }
//        dataSource.reload()

    }
}
